/* color.cc
* This file is part of ncursesxx library
* Copyright (c) 2003,2004 by Stanislav Ievlev
*
* This file is covered by the GNU Library General Public License,
* which should be included with libncursesxx as the file COPYING.
*/
#include <stdexcept>
#include <algorithm>
#include <vector>

#include <ncurses/color.hh>
#include <ncurses/assert.hh>
#include <ncurses/support.hh>

using namespace ncurses;


/**
 * Manager of the pool of available color pairs numbers.
 * This manager uses reference counting to free numbers: each vector element contents
 * a count of this number users.
 */
class pool_impl
{
	typedef std::vector<short> color_vector; /**< vector of colors */
public:
	pool_impl():         /**< fill pool with default values */
			colors_(COLOR_PAIRS)
	{
		std::fill(colors_.begin(), colors_.end(), 0);
	}

	short get() /**< return next available number*/
	{
		color_vector::iterator it = std::find(colors_.begin() + 1,
						      colors_.end(), 0); // find first zero
		if (it != colors_.end())
		{ //new available number was found
			++(*it);
			return std::distance(colors_.begin(), it);
		}
		else
			throw std::runtime_error("pool is empty");
	}

	void get(short num) /**< increase number of this color users */
	{
		if (num >= 0) ++(colors_.at(num)); //register new owner
	}

	void put(short num) /**< put number to the pool, decrease number of this color users */
	{
		if (num >= 0) colors_.at(num)--;
	}
private:
	color_vector	colors_;
};

typedef singleton_holder<pool_impl> pool; /**< singleton pool object */

color::color():
		num_( -1),
		attr_(WA_NORMAL)
{}

color::color(short f, short b, attr_t attr):
		num_(pool::instance().get()),
		attr_(attr)
{
	if (::has_colors())
		NCURSES_ASSERT(::init_pair(num_, f, b));
}

color::color(const color& other):
		num_(other.num_),
		attr_(other.attr_)
{
	pool::instance().get(num_); //get ownership over new number
}

color::~color()
{
	pool::instance().put(num_);
}

void color::swap(color& other)
{
	std::swap(num_, other.num_);
	std::swap(attr_, other.attr_);
}

color& color::operator=(const color& other)
{
	color(other).swap(*this);
	return *this;
}

short color::num() const
{
	return num_;
}

attr_t color::attr() const
{
	return attr_;
}
